#region Header

// MS codename Velocity Distributed Cache Extensions.
// (c) 2009

#endregion


#region Usings

using System;
using System.Globalization;

#endregion


namespace Caching.Extensions.Core
{
    /// <summary>
    /// Cache Key item
    /// </summary>
    /// <remarks>
    /// Used by local cache
    /// </remarks>
    [Serializable]
    public struct SmartCacheKey : IEquatable<SmartCacheKey>
    {
        #region Private Data 

        private readonly string m_cacheName;
        private readonly string m_regionName;
        private readonly string m_key;
        [NonSerialized] private int m_hashCode;

        #endregion Private Data


        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="cacheName">Cache instance name</param>
        /// <param name="key">Item Key</param>
        /// <param name="regionName">Cache region name</param>
        public SmartCacheKey(string cacheName, string key, string regionName)
        {
            if (string.IsNullOrEmpty(cacheName)) throw new ArgumentNullException("cacheName");
            if (string.IsNullOrEmpty(key)) throw new ArgumentNullException("key");

            m_key = key;
            m_cacheName = cacheName;
            m_regionName = (regionName ?? string.Empty);
            m_hashCode = 0;
        }


        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="cacheName">Cache instance name</param>
        /// <param name="key">Item key</param>
        public SmartCacheKey(string cacheName, string key) : this(cacheName, key, string.Empty)
        {
        }


        #region Public Properties 

        /// <summary>
        /// Cache instance name.
        /// Refers to named cache instance
        /// </summary>
        public string CacheName
        {
            get { return m_cacheName; }
        }

        /// <summary>
        /// Cache region name.
        /// Refers to region name in backing cache
        /// </summary>
        public string RegionName
        {
            get { return m_regionName; }
        }

        /// <summary>
        /// Item Key
        /// </summary>
        public string Key
        {
            get { return m_key; }
        }

        #endregion Public Properties


        /// <summary>
        /// Check cache item for equality
        /// </summary>
        /// <param name="other">Other item</param>
        /// <returns>True, if items are equal</returns>
        public bool Equals(SmartCacheKey other)
        {
            return Equals(other.CacheName, CacheName) && Equals(other.RegionName, RegionName) &&
                Equals(other.Key, Key);
        }


        /// <summary>
        /// Check cache item for equality
        /// </summary>
        /// <param name="obj">Other object to compare</param>
        /// <returns>True, if equal</returns>
        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (obj.GetType() != typeof (SmartCacheKey)) return false;
            return Equals((SmartCacheKey) obj);
        }


        public override int GetHashCode()
        {
            if (m_hashCode == 0)
                unchecked
                {
                    int result = (CacheName.GetHashCode());
                    result = (result*397) ^ (RegionName.GetHashCode());
                    result = (result*397) ^ (Key.GetHashCode());
                    m_hashCode = result;
                }
            return m_hashCode;
        }


        public override string ToString()
        {
            return string.Format(CultureInfo.InvariantCulture, "CacheKey:[{0}:{1}:{2}]", m_key, m_regionName,
                m_cacheName);
        }


        public static bool operator ==(SmartCacheKey left, SmartCacheKey right)
        {
            return Equals(left, right);
        }


        public static bool operator !=(SmartCacheKey left, SmartCacheKey right)
        {
            return !Equals(left, right);
        }
    }
}